package com.tjhzzx.ibmsSupervisor.servlet;

import com.tridium.json.JSONObject;
import com.tridium.web.CookieUtil;
import org.apache.commons.lang3.StringUtils;

import javax.baja.web.WebOp;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.net.URLDecoder;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

public abstract class AbstractServletCommand implements PostExecutor, GetExecutor {
    private static final Logger LOGGER = Logger.getLogger(AbstractServletCommand.class.getName());
    protected WebOp op;

    @Override
    public void doPost(WebOp op) throws Exception {
        this.op = op;
        doRequest(op, HttpMethod.POST);
    }

    @Override
    public void doGet(WebOp op) throws Exception {
        this.op = op;
        doRequest(op, HttpMethod.GET);
    }

    private void doRequest(WebOp op, int httpMethod) throws Exception {
        InputStream is = op.getRequest().getInputStream();
        String queryString = "";
        if(StringUtils.isNotBlank(op.getRequest().getQueryString())) {
            queryString = op.getRequest().getQueryString();
        }
        if(httpMethod == HttpMethod.POST) {
            while (0 < is.available()) {
                int length = is.available();
                byte[] messageArray = new byte[length];
                is.read(messageArray);
                if(messageArray.length > 0) {
                    String messageTemp = new String(messageArray, "UTF-8");
                    if (StringUtils.isNotBlank(messageTemp)) {
                        queryString += messageTemp;
                    }
                }
            }
        }
        queryString = URLDecoder.decode(queryString, "UTF-8");
        Cookie sessionIdCookie = getRequestedSessionId(op.getRequest());
        if (sessionIdCookie != null) {
            op.getResponse().addCookie(sessionIdCookie);
        }
        Cookie userIdCookie = getRequestedUsername(op.getRequest());
        if (userIdCookie != null) {
            op.getResponse().addCookie(userIdCookie);
        }
//      process(op, message);
        dispatch(op, queryString, httpMethod);
    }

//    public abstract void process(WebOp op, String message) throws Exception;

    private void dispatch(WebOp op, String queryString, int httpMethod) throws Exception {
        String methodName = "process";
        LOGGER.log(Level.SEVERE, "dispatch queryString b: " + queryString);
        if (StringUtils.isNotBlank(queryString)) {
            String[] params = queryString.split("&");
            for (String param : params) {
                if (param.startsWith("method=")) {
                    methodName = param.substring("method=".length());
                    if(param.length() == queryString.length()) {
                        queryString = "";
                        break;
                    }
                    queryString = queryString.substring(param.length() + 1);
                    break;
                }
            }
        }
        if (httpMethod == HttpMethod.POST) {
            methodName = "post" + toUpperCaseFirstLetter(methodName);
        } else if (httpMethod == HttpMethod.GET) {
            methodName = "get" + toUpperCaseFirstLetter(methodName);
        }
        LOGGER.log(Level.SEVERE, "dispatch methodName: " + methodName);
        LOGGER.log(Level.SEVERE, "dispatch queryString a: " + queryString);
        Method method = null;
        try {
            method = getClass().getDeclaredMethod(methodName, WebOp.class, String.class);
            method.invoke(this, op, queryString);
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("dispatch [" + methodName + "] exception: " + e.getMessage());
        }
    }

    protected void setResponse(String response) {
        try {
            op.getResponse().setContentType("application/json;charset=UTF-8");
            op.getResponse().getWriter().write(response);
            op.getResponse().setStatus(HttpServletResponse.SC_OK);
        } catch (IOException e) {
            LOGGER.log(Level.SEVERE, "setResponse exception!", e);
        }
    }

    protected void jsonResponse(Object object) {
        JSONObject jsonObject = new JSONObject(object);
        setResponse(jsonObject.toString());
    }

    protected void jsonResultResponse(JSONResult jsonResult) {
        setResponse(jsonResult.toJSONString());
    }

    protected void jsonResultResponse(String jsonString) {
        setResponse(jsonString);
    }


    private Cookie getRequestedSessionId(HttpServletRequest request) {
        String sessionCookieId = "JSESSIONID";
        Cookie cookie = CookieUtil.getCookieFromName(request, sessionCookieId);
        if (cookie != null) {
            cookie.setMaxAge(60 * 60 * 365);
            cookie.setPath("/");
        }
        return cookie;
    }

    private Cookie getRequestedUsername(HttpServletRequest request) {
        String userCookieName = "niagara_userid";
        Cookie cookie = CookieUtil.getCookieFromName(request, userCookieName);
        if (cookie != null) {
            cookie.setHttpOnly(true);
            cookie.setMaxAge(60 * 60 * 365);
            cookie.setPath("/");
        }
        return cookie;
    }

    private static String toUpperCaseFirstLetter(String s) {
        if (Character.isUpperCase(s.charAt(0))) {
            return s;
        }
        else {
            return (new StringBuilder()).append(Character.toUpperCase(s.charAt(0))).append(s.substring(1)).toString();
        }
    }

    protected Map<String, Object> resolveParams(String queryString) {
        Map<String, Object> params = new HashMap<>();
        if (StringUtils.isNotBlank(queryString)) {
            String[] strings = queryString.split("&");
            for(String string : strings) {
                String[] entry = string.split("=");
                if(entry != null && entry.length == 2) {
                    params.put(entry[0], entry[1]);
                }
            }
        }
        LOGGER.log(Level.SEVERE, "[resolveParams]: " + params);
        return params;
    }
}